#include "get_arg.h"


#include <boost/program_options/options_description.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/lexical_cast.hpp>
// link with -lboost_filesystem-gcc -lboost_program_options-gcc
// program_options_helper.cpp


#include <iostream>
#include <string>
#include <set>
#include <cmath>




// my functions
#define DEBUG_LEVEL 6
#include <debug_func.h>
#include <ultoa.h>
#include <print_error.h>
#include <stdexcept>
#include <program_options_helper.h>

using std::string;
using std::cerr;
using std::ofstream;
using std::cerr;
using std::cout;
using boost::filesystem::path;
using boost::filesystem::extension;
using boost::filesystem::basename;
using boost::lexical_cast;


using namespace program_options_helper;
namespace po = boost::program_options_lg;

//_______________________________________________________________________________________

//		process_command_line_options

//				from command line
//				Created [9/13/2001]

//_______________________________________________________________________________________
bool process_command_line_options(int argc, char* argv[], t_program_args& args)
{
	char input_format, output_format;


	// mandatory arguments
	string matrix_file_name;
	po::options_description mandatory_args("Mandatory Arguments");
	mandatory_args.add_options()
	("unchanged_tree_file,u", po::value<string>(&args.unchanged_tree_file)
										->set_name("FILE"),
										"Output file for trees which have not had "
										"sub-branches extracted.");

	args.optional_args.add_options()
	("tree_files_path,t", po::value<string>(&args.tree_files)
										->set_name("PATH"),
										"Output files that will contain each sub-tree in "
										"New Hampshire format")
	("sub_matrix_files_path,s", po::value<string>(&args.matrix_files)
											->set_name("PATH"),
									"Output files for matrices corresponding to each "
									"extracted branch.")
	("description,d", po::value<string>(&args.description)
											->set_name("TEXT"),
										"The extracted sub-tree names will have this "
										"value appended.")
	("leaf_number_max,l", po::value<unsigned>(&args.node_limit)
											->set_name("COUNT")
											->default_value(50),
										"Extract branches with fewer than COUNT "
										"number of leaves.")
	("branch_length_limit,b", po::value<float>(&args.len_limit)
											->set_name("LENGTH")
											->default_value(2.5),
										"Extract branches with any leaf to branch "
										"distances longer than LENGTH.")
	("input_format,i", po::value<char>(&input_format)
										->default_value('p')
										->set_name("FORMAT"),
									"Input matrix format.\x1"
									"FORMAT = b / p / s / l \x1"
									"binary: b, pairs: p, square: s,\x1"
									"lower triangular: l")
	("output_format,o", po::value<char>(&output_format)->default_value('p')->set_name("FORMAT"),
									"Output matrix format.\x1"
									"FORMAT = b / p / s / l");

	args.add_std_options();
	po::options_description all_args("");
	all_args
			.add(mandatory_args)
			.add(args.optional_args);

	// parse command line
	po::variables_map vm;
	po::store(po::command_line_parser(argc, argv).options(all_args).run(), vm);
	po::notify(vm);

	if (vm.count("version"))
	{
		print_version(cerr, *argv, "1.2\n"
			"\tHistory: \n\n"
			"\tv 1.0\1"
			"27-09-2004\1"
  			"Initial version\n"
			"\tv 1.1\1"
			"01-02-2005\1"
			"Split programme so that vanilla version does not do anything with matrices.\n"
			);
		return false;
	}
	if (vm.count("help"))
	{
		string exe_description =
			"Takes interleaved New Hampshire trees and matrices "
			"via STDIN (each tree followed by its corresponding matrix) "
			"and extracts all large sub-branches: "
			"those longer than a specified limit but with fewer than a specified "
			"number of leaves.\n"
			"The original tree is written to STDOUT with placeholders corresponding to the "
			"extracted subbranches (e.g. SUB_XXXX77).\n"
			"Files are written to PATH with successive numerical suffices added "
			"to the file name, e.g. \"\\path\\tree.nh\" becomes "
			"\"\\path\\tree----1.nh\"\n";

		print_usage(cerr, *argv, "[OPTIONS] < TREE_MATRIX_FILE",
									all_args, exe_description, 80);
		return false;
	}

	check_required_options(vm, mandatory_args);


	if (!vm.count("tree_files_path") && !vm.count("sub_matrix_files_path"))
		throw std::runtime_error("Please specify matrix or tree output (or both).");



	// output/input formats
	select_matrix_file_format(output_format, args.output_format, "output");
	select_matrix_file_format(input_format, args.input_format, "input");



	args.open_err_log();
	return true;
}




namespace{
void open_file(ofstream& ostrm, const string& file_name, const string& subscript)
{
	if (file_name.length())
	{
		if (ostrm.is_open())
			 ostrm.close();
		try
		{
			path orig_path(file_name, boost::filesystem::native);
			path newname(orig_path.branch_path());
			newname /= path(basename(orig_path) + subscript + extension(orig_path),
							boost::filesystem::native);
			ostrm.open(newname.string().c_str());
		}
		catch (std::exception const & e)
		{
			throw std::runtime_error("Could not open the file (" + file_name + ") "
					"for saving the data matrix:\n"
					+ file_name + " is not a valid path.");

		}
		if (!ostrm.good())
		{
			throw std::runtime_error("Could not open the file (" + file_name + ") "
					"for saving the data matrix.\n");
		}
	 }
	return;
}
}
void t_program_args::open_output_files(unsigned i)
{
	string subscript = lexical_cast<string>(i);
	subscript = string(5 - subscript.length(), '-') + subscript;

	if (matrix_files.length())
		open_file(f_matrix_file, matrix_files, subscript);
	if (tree_files.length())
		open_file(f_tree_file, tree_files, subscript);
}
